/**************************************************************************** 
 * Meta，一个轻量级的静态分区Hypervisor 
 *
 * 版权(c) , 2022-
 *
 * 作者:
 *      Tupelo Shen <shenwanjiang2013@163.com>
 *
 * Meta是一个自由软件，你可以在遵循GNU GPLv2协议的条件下，重新修改并发布它。
 *
 ***************************************************************************/

#include <arch/gic.h>
#include <cpu.h>
#include <platform.h>
#include <interrupts.h>

/* GICD寄存器组变量定义，位于.devices段，按照page页大小对齐，默认是4K */
volatile struct gicd_hw     gicd __attribute__((section(".devices"), aligned(PAGE_SIZE)));
spinlock_t                  gicd_lock;

/****************************************************************************
 ****                       私有函数接口                                 ****
 ****************************************************************************/
static void gicd_init();

/****************************************************************************
 ****                       公共函数接口                                 ****
 ****************************************************************************/
void gic_map_mmio();

/****************************************************************************
 ****                       公共函数定义                                 ****
 ****************************************************************************/
/**
 * 功能描述: 初始化GIC，公共部分由主核初始化，私有部分由核自身处理：
 *           (1) 映射GIC对应的设备内存（主核）
 *              (GICD保存在./device段，GICR保存在Hyp的全局内存段)
 *           (2) 初始化GICD（主核）
 *           (3) 获取列表寄存器的数量（主核）
 *           (4) 初始化CPU interface（每个核）
 * 入口参数: void
 * 出口参数: void
 * 返 回 值: void
 * 修改日期: 2022-09-21
 */
void gic_init(void)
{
    if (cpu.id == CPU_MASTER) {
        gic_map_mmio();
        gicd_init();
        g_num_lrs = gich_num_lrs();
    }

    /* 屏障指令，保证写内存完成 */
    cpu_sync_barrier(&cpu_glb_sync);

    /* 初始化CPU interface */
    gic_cpu_init();
}

/**
 * 功能描述: 中断处理函数
 *           GIC公共部分由主核初始化，私有部分由核自身处理。
 * 入口参数: void
 * 出口参数: void
 * 返 回 值: void
 * 修改日期: 2022-09-21
 */
void gic_handle()
{
    uint32_t ack    = gicc_iar();
    irqid_t id      = bit32_extract(ack, GICC_IAR_ID_OFF, GICC_IAR_ID_LEN);

    if (id < GIC_FIRST_SPECIAL_INTID) {
        enum irq_res res = interrupts_handle(id);
        gicc_eoir(ack);
        if (res == HANDLED_BY_HYP) gicc_dir(ack);
    }
}

uint8_t gicd_get_prio(irqid_t int_id)
{
    size_t reg_ind = GIC_PRIO_REG(int_id);
    size_t off = GIC_PRIO_OFF(int_id);

    uint8_t prio =
        gicd.IPRIORITYR[reg_ind] >> off & BIT32_MASK(off, GIC_PRIO_BITS);

    return prio;
}

/**
 * 功能描述: GICD distributor分发器的初始化（属于中断控制器的全局设置）
 *           将GICD相关寄存器设置为无效状态
 *           GICv2和GICv3&v4有些寄存器配置不一样
 * 入口参数: void
 * 出口参数: void
 * 返 回 值: void
 * 修改日期: 2022-09-21
 */
static void gicd_init()
{
    size_t int_num = gic_num_irqs();

    /**
     * 将distributor初始化为已知状态;
     * i的取值从1开始，忽略掉前32个私有中断
     */
    for (size_t i = GIC_NUM_PRIVINT_REGS; i < GIC_NUM_INT_REGS(int_num); i++) {
        /* 确保所有的中断处于禁止、未挂起、无效状态 */
        gicd.ICENABLER[i]   = -1;
        gicd.ICPENDR[i]     = -1;
        gicd.ICACTIVER[i]   = -1;
    }

    /* 默认情况下，所有中断具有最低优先级 */
    for (size_t i = GIC_NUM_PRIO_REGS(GIC_CPU_PRIV);
         i < GIC_NUM_PRIO_REGS(int_num); i++) {
        gicd.IPRIORITYR[i] = -1;
    }

    if (GIC_VERSION == GICV2) {
        /* 默认情况下，中断没有目标核 */
        for (size_t i = GIC_NUM_TARGET_REGS(GIC_CPU_PRIV);
             i < GIC_NUM_TARGET_REGS(int_num); i++) {
            gicd.ITARGETSR[i] = 0;
        }

        /* 使能distributor */
        gicd.CTLR |= GICD_CTLR_EN_BIT;

    } else {
        for (size_t i = GIC_CPU_PRIV; i < GIC_MAX_INTERUPTS; i++) {
            gicd.IROUTER[i] = GICD_IROUTER_INV;
        }

        /* 使能distributor和亲和力路由 */
        gicd.CTLR |= GICD_CTLR_ARE_NS_BIT | GICD_CTLR_ENA_BIT;
    }

    /* ICFGR依赖于硬件平台，保持原样即可 */

    /* 无需设置gicd.NSACR，因为所有中断都设置为Group 1 */

    /* 注册维护中断（默认中断号id为25）*/
    interrupts_reserve(platform.arch.gic.maintenance_id,
                       gic_maintenance_handler);
}

/**
 * 功能描述: 设置Distributor上对应共享中断的pending状态
 * 入口参数: int_id:    中断ID
 *           pend:      中断挂起状态
 * 出口参数: void
 * 返 回 值: void
 * 修改日期: 2022-09-21
 */
void gicd_set_pend(irqid_t int_id, bool pend)
{
    size_t reg_ind = GIC_INT_REG(int_id);
    if (pend) {
        gicd.ISPENDR[reg_ind] = GIC_INT_MASK(int_id);
    } else {
        gicd.ICPENDR[reg_ind] = GIC_INT_MASK(int_id);
    }
}

/**
 * 功能描述: 设置Distributor上对应共享中断的active状态
 * 入口参数: int_id:    中断ID
 *           act:       中断active状态
 * 出口参数: void
 * 返 回 值: void
 * 修改日期: 2022-09-21
 */
void gicd_set_act(irqid_t int_id, bool act)
{
    size_t reg_ind = GIC_INT_REG(int_id);

    if (act) {
        gicd.ISACTIVER[reg_ind] = GIC_INT_MASK(int_id);
    } else {
        gicd.ICACTIVER[reg_ind] = GIC_INT_MASK(int_id);
    }
}

/**
 * 功能描述: 获取Distributor上对应共享中断的pending状态
 * 入口参数: int_id:    中断ID
 * 出口参数: void
 * 返 回 值: bool
 * 修改日期: 2022-09-21
 */
bool gicd_get_pend(irqid_t int_id)
{
    return (gicd.ISPENDR[GIC_INT_REG(int_id)] & GIC_INT_MASK(int_id)) != 0;
}

/**
 * 功能描述: 获取Distributor上对应共享中断的active状态
 * 入口参数: int_id:    中断ID
 * 出口参数: void
 * 返 回 值: bool
 * 修改日期: 2022-09-21
 */
bool gicd_get_act(irqid_t int_id)
{
    return (gicd.ISACTIVER[GIC_INT_REG(int_id)] & GIC_INT_MASK(int_id)) != 0;
}

/**
 * 功能描述: 设置Distributor的共享中断的使能位
 * 入口参数: int_id:    中断ID
 *           en:        使能位
 * 出口参数: void
 * 返 回 值: void
 * 修改日期: 2022-09-21
 */
void gicd_set_enable(irqid_t int_id, bool en)
{
    size_t reg_ind = GIC_INT_REG(int_id);
    uint32_t bit = GIC_INT_MASK(int_id);

    if (en) {
        gicd.ISENABLER[reg_ind] = bit;
    } else {
        gicd.ICENABLER[reg_ind] = bit;
    }
}

/**
 * 功能描述: 设置Distributor的共享中断的优先级
 * 入口参数: int_id:    中断ID
 *           prio:      优先级
 * 出口参数: void
 * 返 回 值: void
 * 修改日期: 2022-09-21
 */
void gicd_set_prio(irqid_t int_id, uint8_t prio)
{
    size_t reg_ind = GIC_PRIO_REG(int_id);
    size_t off = GIC_PRIO_OFF(int_id);
    uint32_t mask = BIT32_MASK(off, GIC_PRIO_BITS);

    spin_lock(&gicd_lock);

    gicd.IPRIORITYR[reg_ind] =
        (gicd.IPRIORITYR[reg_ind] & ~mask) | ((prio << off) & mask);

    spin_unlock(&gicd_lock);
}

/**
 * 功能描述: 设置Distributor的中断配置
 * 入口参数: int_id,    目标核
 *           cfg,       配置
 * 出口参数: void
 * 返 回 值: void
 * 修改日期: 2022-09-21
 */
void gicd_set_icfgr(irqid_t int_id, uint8_t cfg)
{
    size_t reg_ind = (int_id * GIC_CONFIG_BITS) / (sizeof(uint32_t) * 8);
    size_t off = (int_id * GIC_CONFIG_BITS) % (sizeof(uint32_t) * 8);
    uint32_t mask = ((1U << GIC_CONFIG_BITS) - 1) << off;

    spin_lock(&gicd_lock);

    gicd.ICFGR[reg_ind] = (gicd.ICFGR[reg_ind] & ~mask) | ((cfg << off) & mask);

    spin_unlock(&gicd_lock);
}